import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Map;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Constants;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSInterface;
import com.speljohan.rsbot.script.wrappers.RSItemTile;
import com.speljohan.rsbot.script.wrappers.RSNPC;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSPlayer;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class ExemptAlKharidSlayer extends Script implements PaintListener {

	int mobID[] = { 18 };
	int arrowID;
	int eatAt;
	int bankID = 35647;
	int combat = 0;
	boolean dw = false;
	boolean paint;
	boolean banking;
	boolean eatFood;
	boolean pickArrow;
	boolean bury = false;
	boolean buryBones = false;
	boolean bonePickup = false;
	int trainStat;
	int style = 0;
	int startStatLvl;
	int startXp;
	int startExp;
	int boneID = 526;
	String foodAmount = "Withdraw-10";
	RSPlayer self = getMyPlayer();
	public long startTime = System.currentTimeMillis();
	Color BG = new Color(70, 234, 40, 100);
	private static RSTile current = new RSTile(0, 0);
	int[] foodID = { 1895, 1893, 1891, 4293, 2142, 291, 2140, 3228, 9980, 7223,
			6297, 6293, 6295, 6299, 7521, 9988, 7228, 2878, 7568, 2343, 1861,
			13433, 315, 325, 319, 3144, 347, 355, 333, 339, 351, 329, 3381,
			361, 10136, 5003, 379, 365, 373, 7946, 385, 397, 391, 3369, 3371,
			3373, 2309, 2325, 2333, 2327, 2331, 2323, 2335, 7178, 7180, 7188,
			7190, 7198, 7200, 7208, 7210, 7218, 7220, 2003, 2011, 2289, 2291,
			2293, 2295, 2297, 2299, 2301, 2303, 1891, 1893, 1895, 1897, 1899,
			1901, 7072, 7062, 7078, 7064, 7084, 7082, 7066, 7068, 1942, 6701,
			6703, 7054, 6705, 7056, 7060, 2130, 1985, 1993, 1989, 1978, 5763,
			5765, 1913, 5747, 1905, 5739, 1909, 5743, 1907, 1911, 5745, 2955,
			5749, 5751, 5753, 5755, 5757, 5759, 5761, 2084, 2034, 2048, 2036,
			2217, 2213, 2205, 2209, 2054, 2040, 2080, 2277, 2225, 2255, 2221,
			2253, 2219, 2281, 2227, 2223, 2191, 2233, 2092, 2032, 2074, 2030,
			2281, 2235, 2064, 2028, 2187, 2185, 2229, 6883 };
	public RSTile[] toMobs = new RSTile[] { new RSTile(3270, 3167),
			new RSTile(3276, 3175), new RSTile(3284, 3183),
			new RSTile(3292, 3180), new RSTile(3294, 3175),
			new RSTile(3300, 3172) };
	public RSTile[] toBank = reversePath(toMobs);

	public RSTile[] deathwalk = new RSTile[] { new RSTile(3222, 3219),
			new RSTile(3228, 3219), new RSTile(3235, 3222),
			new RSTile(3241, 3225), new RSTile(3249, 3226),
			new RSTile(3249, 3231), new RSTile(3253, 3239),
			new RSTile(3255, 3246), new RSTile(3253, 3252),
			new RSTile(3251, 3258), new RSTile(3250, 3265),
			new RSTile(3247, 3273), new RSTile(3242, 3276),
			new RSTile(3238, 3283), new RSTile(3239, 3290),
			new RSTile(3239, 3299), new RSTile(3240, 3306),
			new RSTile(3244, 3309), new RSTile(3248, 3314),
			new RSTile(3253, 3319), new RSTile(3260, 3324),
			new RSTile(3266, 3325), new RSTile(3272, 3331),
			new RSTile(3281, 3328), new RSTile(3279, 3320),
			new RSTile(3277, 3310), new RSTile(3275, 3302),
			new RSTile(3274, 3292), new RSTile(3271, 3285),
			new RSTile(3270, 3276), new RSTile(3272, 3268),
			new RSTile(3273, 3261), new RSTile(3274, 3253),
			new RSTile(3275, 3245), new RSTile(3275, 3238),
			new RSTile(3275, 3229), new RSTile(3275, 3220),
			new RSTile(3275, 3211), new RSTile(3275, 3203),
			new RSTile(3274, 3196), new RSTile(3280, 3193),
			new RSTile(3201, 3186), new RSTile(3278, 3178),
			new RSTile(3275, 3170), new RSTile(3270, 3167) };

	public void atItem(final String option, final int... itemID) {
		if (getCurrentTab() != Constants.TAB_INVENTORY
				&& !RSInterface.getInterface(Constants.INTERFACE_BANK)
						.isValid()
				&& !RSInterface.getInterface(Constants.INTERFACE_STORE)
						.isValid()) {
			openTab(Constants.TAB_INVENTORY);
		}
		final int[] items = getInventoryArray();
		final java.util.List<Integer> possible = new ArrayList<Integer>();
		for (int i = 0; i < items.length; i++) {
			for (final int element : itemID) {
				if (items[i] == element) {
					possible.add(i);
				}
			}
		}
		if (possible.size() > 0) {
			final Point t = getInventoryItemPoint(possible.get(0));
			moveMouse(t, 2, 2);
			if (getMenuItems().get(0).contains(option)) {
				clickMouse(t, 5, 5, true);
			} else {
				clickMouse(t, 5, 5, false);
				atMenu(option);
			}
		}
	}

	public void bankClose() {
		final int randx = random(484, 492);
		final int randy = random(31, 39);
		final Point p = new Point(randx, randy);
		wait(random(1000, 1500));
		clickMouse(p, 1, 1, true);
	}

	public void checkEat() {
		final int curHP = skills.getCurrentSkillLevel(Constants.STAT_HITPOINTS);
		final int eat = random(eatAt, (eatAt + 3));
		if (curHP <= eat && getInventoryCount(foodID) > 0) {
			atItem("Eat", foodID);
		}
		if (getInventoryCount(foodID) <= 0) {
			banking = true;
			walkMM(randomizePath(toBank, 2, 2), 15);
			useBank();
		} else {
			banking = false;
		}
	}

	@Override
	public String getAuthor() {
		return "Exempt";
	}

	@Override
	public String getName() {
		return "ExemptAlKharidSlayer";
	}

	// Game info start************************
	@Override
	public String getScriptCategory() {
		return "Combat";
	}

	@Override
	public String getScriptDescription() {
		String html = "";

		html += "<html>";
		html += "<body>";
		html += "<font size=\"8\">";
		html += "<b>" + getName() + " v" + getVersion() + "</b><br>";
		html += "<font size=\"6\">";
		html += "Author: " + getAuthor() + "<br><br>";
		html += "<font size=\"4\">";
		html += "<input type=checkbox name=paint value=true> Disable paint</input><br>";
		html += "<input type=checkbox name=eatFood value=true> Disable eating</input><br>";
		html += "<input type=checkbox name=pickArrow value=true> Disable arrow pickup</input><br>";
		html += "If arrow pickup is enabled input arrow ID: <input type=\"text\" name=\"arrowID\"><br><br>";
		html += "Range: <input type=checkbox name=range value=true></input><br>";
		html += "Melee: <input type=checkbox name=melee value=true></input><br>";
		html += "If you choose melee input: (1)Attack (2)Strength (3)Defense <input type=\"text\" name=\"style\"><br><br>";
		html += "When you want to eat. Example: 25 Note: it will add random 1-3.<br>";
		html += "When to eat: <input type=\"text\" name=\"eatAt\"><br><br>";
		html += "Bone pick will pick up bones till your inventory is full then store.<br>";
		html += "<input type=checkbox name=bonePickup value=true> Enable bone pickup</input><br>";
		html += "If you tick this the script will bury bones instead of storing them.<br>";
		html += "<input type=checkbox name=bury value=true> Enable bone bury</input><br>";
		html += "</font>";
		html += "</body>";
		html += "</html>";

		return html;
	}

	@Override
	public double getVersion() {
		return 3.0;
	}

	public boolean hasEquippedOneOf(final int... itemIDs) {
		final int[] equipItems = RSInterface.getInterface(387).getChild(29)
				.getInventory();
		for (int j = 0; j < itemIDs.length; j++) {
			for (int i = 0; i < equipItems.length; i++) {
				if (i == j) {
					return true;
				}
			}
		}
		return false;
	}

	// *******************************************************************
	// *******************************Main Loop**************************
	@Override
	public int loop() {
		runControl();
		if (getPlane() == 0) {
			if (dw == false) {
				if (eatFood) {
					checkEat();
				}
				if (pickArrow) {
					if (!self.isInCombat() && self.getInteracting() == null) {
						if (inventoryContains(arrowID)) {
							if (getInventoryItemByID(arrowID).getStackSize() > random(
									38, 65)) {
								atInventoryItem(arrowID, "Wield");
							}
						}
						final RSItemTile arrow = getGroundItemByID(10, arrowID);
						if (arrow != null && !self.isMoving()) {
							atTile(arrow, "Take");
							return random(200, 300);
						}
					}
				}
				if (bonePickup) {
					if (!self.isInCombat() && self.getInteracting() == null) {
						if (inventoryContains(boneID)) {
							if (isInventoryFull()) {
								banking = true;
								walkMM(randomizePath(toBank, 2, 2), 15);
								useBank();
							}
						}
						final RSItemTile bone = getGroundItemByID(2, boneID);
						if (bone != null && !self.isMoving()
								&& buryBones == false) {
							atTile(bone, "Take Bones");
							return random(200, 300);
						}
						if (bury == true) {
							if (getInventoryCount(boneID) >= 5) {
								buryBones = true;
							}
							if (buryBones) {
								atItem("Bury", boneID);
								wait(random(200, 300));
								if (getInventoryCount(boneID) <= 0) {
									buryBones = false;
								}
								return random(50, 100);
							}
						}
					}
				}
				if (combat == 2) {
					if (!hasEquippedOneOf(arrowID)) {
						log("Out of arrows");
						walkMM(randomizePath(toBank, 2, 2), 15);
						stopAllScripts();
						logout();
					}
				}
				if (distanceTo(toMobs[toMobs.length - 1]) > 20
						&& banking == false) {
					walkMM(randomizePath(toMobs, 2, 2), 15);
				}
				if (!self.isInCombat() && self.getInteracting() == null
						&& !self.isMoving() && banking == false
						&& getNearestFreeNPCByID(mobID) != null) {
					final RSNPC mob = getNearestFreeNPCByID(mobID);
					final Point loc = Calculations.tileToScreen(mob
							.getLocation());
					moveMouse(loc, 5, 5);
					if (getMenuItems().get(0).contains("Attack")
							&& canReach(mob, true)) {
						clickMouse(loc, 5, 5, true);
						return random(50, 100);
					} else {
						atNPC(mob, "Attack");
						return random(50, 100);
					}
				}
			}
			if (distanceTo(toMobs[0]) > 50) {
				dw = true;
			}
			if (dw) {
				if (combat == 1) {
					walkMM(randomizePath(deathwalk, 2, 2), 5);
					if (distanceTo(deathwalk[deathwalk.length - 1]) < 4) {
						if (getInventoryCount() == 3) {
							if (getCurrentTab() != Constants.TAB_INVENTORY
									&& !RSInterface.getInterface(
											Constants.INTERFACE_BANK).isValid()
									&& !RSInterface.getInterface(
											Constants.INTERFACE_STORE)
											.isValid()) {
								openTab(Constants.TAB_INVENTORY);
							}
							final Point t = getInventoryItemPoint(0);
							clickMouse(t, 2, 2, true);
							wait(random(500, 800));
							final Point y = getInventoryItemPoint(1);
							clickMouse(y, 2, 2, true);
							wait(random(500, 800));
							final Point u = getInventoryItemPoint(2);
							clickMouse(u, 2, 2, true);
						}
						dw = false;
					}
				} else {
					log("Deathwalk diabled cause your using range");
					stopAllScripts();
					logout();
				}
			}
		} else {
			final RSTile tile = new RSTile(3285, 3164);
			if (distanceTo(tile) > 4) {
				walkTileMM(randomizeTile(tile, 1, 1));
			} else {
				final RSObject stair = findObject(35533);
				if (stair != null) {
					atObject(stair, "Climb-down");
					wait(random(500, 1000));
				}
			}
		}
		return random(50, 100);
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
		log("Exiting Exempt's script");
	}

	public void onRepaint(final Graphics g) {
		if (isLoggedIn() && paint == true) {
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			final int LevelChange = skills.getCurrentSkillLevel(trainStat)
					- startStatLvl;
			final int XPChange = skills.getCurrentSkillExp(trainStat) - startXp;
			float xpPerSec = 0;
			if ((minutes > 0 || hours > 0 || seconds > 0) && XPChange > 0) {
				xpPerSec = (float) XPChange
						/ (float) (seconds + minutes * 60 + hours * 60 * 60);
			}
			final float xpPerMin = xpPerSec * 60;
			final float xpPerHour = xpPerMin * 60;
			final float timeTillLvl = 9999;
			float secsTillLvl = (int) timeTillLvl;
			float minsTillLvl = (int) timeTillLvl;
			float hoursTillLvl = (int) timeTillLvl;
			if (xpPerSec > 0) {
				secsTillLvl = skills.getXPToNextLevel(trainStat) / xpPerSec;
			}
			if (xpPerMin > 0) {
				minsTillLvl = skills.getXPToNextLevel(trainStat) / xpPerMin;
			}
			if (xpPerHour > 0) {
				hoursTillLvl = skills.getXPToNextLevel(trainStat) / xpPerHour;
			}
			secsTillLvl -= (int) minsTillLvl * 60;
			minsTillLvl -= (int) hoursTillLvl * 60;

			if (minsTillLvl < 0) {
				minsTillLvl = 0;
			}
			g.setColor(BG);
			g.fill3DRect(330, 20, 184, 75, true);
			g.setColor(Color.black);
			g.drawString("ExemptAlKharidSlayer v2.1", 334, 38);
			g.drawString("Runtime: " + hours + "h " + minutes + "m " + seconds
					+ "s ", 334, 48);
			g.drawString("Levels Gained: " + LevelChange, 334, 58);
			g
					.drawString("Exp Gained: "
							+ (skills.getCurrentSkillExp(trainStat) - startXp),
							334, 68);
			g.drawString("Exp/Hr: " + (int) xpPerHour, 334, 78);
		}
	}

	@Override
	public boolean onStart(final Map<String, String> args) {
		log("Starting ExemptAlKharidSlayer v2.1");
		log("getPlane() " + getPlane());
		if (args.get("pickArrow") == null) {
			pickArrow = true;
			arrowID = Integer.parseInt(args.get("arrowID"));
			log("Arrow pickup enabled");
		} else {
			pickArrow = false;
			log("Arrow pickup disabled");
		}
		if (args.get("bonePickup") == null) {
			bonePickup = false;
			log("Bone pickup disabled");
		}
		if (args.get("bonePickup") != null && args.get("bury") == null) {
			bonePickup = true;
			foodAmount = "Withdraw-5";
			log("Bone pickup and storing enabled");
		}
		if (args.get("bonePickup") != null && args.get("bury") != null) {
			bury = true;
			bonePickup = true;
			foodAmount = "Withdraw-10";
			log("Bone pickup and bury enabled");
		}
		if (args.get("eatFood") == null) {
			eatFood = true;
			eatAt = Integer.parseInt(args.get("eatAt"));
			log("Food enabled");
			log("When to eat: " + eatAt + " Note: I will add randonly 1-3");
		} else {
			eatFood = false;
			banking = false;
			log("Food disabled");
		}
		if (args.get("paint") == null) {
			paint = true;
			log("Paint enabled");
		} else {
			paint = false;
			log("Paint disabled.");
		}
		if (args.get("melee") != null) {
			combat = 1;
			style = Integer.parseInt(args.get("style"));
			if (style == 1) {
				trainStat = Constants.STAT_ATTACK;
			} else if (style == 2) {
				trainStat = Constants.STAT_STRENGTH;
			} else if (style == 3) {
				trainStat = Constants.STAT_DEFENSE;
			} else {
				return false;
			}
			log("Combat style melee");
		} else if (args.get("range") != null) {
			combat = 2;
			trainStat = Constants.STAT_RANGE;
			log("Combat style range");
		} else if (combat == 0) {
			log("No combat style selected. Ending script");
			return false;
		}
		startStatLvl = skills.getCurrentSkillLevel(trainStat);
		startXp = skills.getCurrentSkillExp(trainStat);
		startExp = skills.getCurrentSkillExp(trainStat);
		return true;
	}

	private void runControl() {
		if (!isRunning() && getEnergy() > random(20, 30)) {
			setRun(true);
		}
	}

	public void useBank() {
		if (!getMyPlayer().isMoving() && findObject(bankID) != null) {
			setCompass('w');
			setCameraAltitude(true);
			final RSObject booth = findObject(bankID);
			atObject(booth, "Use-quickly");
		} else {
			wait(random(500, 1000));
		}
		if (RSInterface.getInterface(Constants.INTERFACE_BANK).isValid()) {
			bank.depositAllExcept(arrowID);
			wait(random(400, 800));
			final int randx = random(46, 57);
			final int randy = random(101, 114);
			final Point p = new Point(randx, randy);
			if (eatFood == true && bonePickup == false) {
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
			}
			if (eatFood == true && bonePickup == true && bury == false) {
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
				wait(random(100, 300));
			}
			if (eatFood == true && bonePickup == true && bury == true) {
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
			}
			if (bury == false && bonePickup == false) {
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
			}
			if (bury == false && bonePickup == true) {
				clickMouse(p, 1, 1, false);
				wait(random(100, 300));
				atMenu(foodAmount);
				wait(random(100, 300));
			}
			if (bury == true && bonePickup == false) {
				atMenu(foodAmount);
				clickMouse(p, 1, 1, false);
				wait(random(500, 800));
				atMenu(foodAmount);
				wait(random(100, 300));
			}
			bankClose();
			banking = false;
		}
	}

	// Game info end*************************
	public boolean walkMM(final RSTile[] path, final int maxDist) {
		try {
			final RSTile next = nextTile(path, maxDist);
			if (next != null && !next.equals(ExemptAlKharidSlayer.current)
					&& distanceTo(getDestination()) < random(5, 8)
					|| !self.isMoving()) {
				walkTileMM(next);
				ExemptAlKharidSlayer.current = next;
				return false;
			} else if (next != null
					&& next.equals(ExemptAlKharidSlayer.current)) {
				return false;
			}
		} catch (final Exception e) {
			return false;
		}
		return true;
	}
}